#include "stdafx.h"
#include "cz_file.h"
#include "cz_log.h"
#include "cz_string.h"
#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "shell32.lib")

wstring cz_file_in_GetDoubleNullPathW(IN wstringc& wcsPath);
string cz_file_in_GetDoubleNullPathA(IN stringc& strPath);




/* BrowseDirX ----------------------------------------------------------------------------------------------*/
bool cz_file_BrowseDirW(IN wstringc& wcsDir, IN cz_file_callback_BrowseDirW pfDoBrowseDirW, IN void* pUserData)
{
	if (!cz_file_IsDirFormatW(wcsDir))
	{
		CZ_LOG_ERRORW(L"");
		return false;
	}

	bool r = false;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATAW wfd;
	_CZ_FILE_RESULT t;

	hFind = FindFirstFileW((wcsDir + L"*").c_str(), &wfd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		CZ_LOG_ERRORW(L"");
		goto L_End;
	}

	do 
	{
		if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
		{
			if ((wcscmp(wfd.cFileName, L".") != 0) && (wcscmp(wfd.cFileName, L"..") != 0))
			{
				t = pfDoBrowseDirW(wcsDir + wfd.cFileName + L"\\", pUserData);
				if (t == CZ_FILE_ERROR)
				{
					CZ_LOG_ERRORW(L"");
					goto L_End;
				}
				if (t != CZ_FILE_SKIP)
				{
					if (!cz_file_BrowseDirW(wcsDir + wfd.cFileName + L"\\", pfDoBrowseDirW, pUserData))
					{
						CZ_LOG_ERRORW(L"");
						goto L_End;
					}
				}
			}
		}
		else
		{
			t = pfDoBrowseDirW(wcsDir + wfd.cFileName, pUserData);
			if (t == CZ_FILE_ERROR)
			{
				CZ_LOG_ERRORW(L"");
				goto L_End;
			}
		}

		if (FindNextFileW(hFind, &wfd) == FALSE)
		{
			if (GetLastError() != ERROR_NO_MORE_FILES)
			{
				CZ_LOG_ERRORW(L"");
				goto L_End;
			}
			break;
		}

	} while (true);

	r = true;

L_End:
	if (hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
	return r;
}

bool cz_file_BrowseDirA(IN stringc& strDir, IN cz_file_callback_BrowseDirA pfDoBrowseDirA, IN void* pUserData)
{
	if (!cz_file_IsDirFormatA(strDir))
	{
		CZ_LOG_ERRORA("");
		return false;
	}

	bool r = false;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATAA wfd;
	_CZ_FILE_RESULT t;

	hFind = FindFirstFileA((strDir + "*").c_str(), &wfd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		CZ_LOG_ERRORA("");
		goto L_End;
	}

	do 
	{
		if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
		{
			if ((strcmp(wfd.cFileName, ".") != 0) && (strcmp(wfd.cFileName, "..") != 0))
			{
				t = pfDoBrowseDirA(strDir+wfd.cFileName + "\\", pUserData);
				if (t == CZ_FILE_ERROR)
				{
					CZ_LOG_ERRORA("");
					goto L_End;
				}
				if (t != CZ_FILE_SKIP)
				{
					if (!cz_file_BrowseDirA(strDir + wfd.cFileName + "\\", pfDoBrowseDirA, pUserData))
					{
						CZ_LOG_ERRORA("");
						goto L_End;
					}
				}
			}
		}
		else
		{
			t = pfDoBrowseDirA(strDir + wfd.cFileName, pUserData);
			if (t == CZ_FILE_ERROR)
			{
				CZ_LOG_ERRORA("");
				goto L_End;
			}
		}

		if (FindNextFileA(hFind, &wfd) == FALSE)
		{
			if (GetLastError() != ERROR_NO_MORE_FILES)
			{
				CZ_LOG_ERRORA("");
				goto L_End;
			}
			break;
		}

	} while (true);

	r = true;

L_End:
	if (hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
	return r;
}

/* DeletePathX ---------------------------------------------------------------------------------------------*/
bool cz_file_DeletePathW(IN wstringc& wcsPath, u32 flag /* = CZ_FILE_NULL */)
{
	if (!cz_file_IsPathExistsW(wcsPath)) return true;

	SHFILEOPSTRUCTW sos;
	wstring wcsFrom = cz_file_in_GetDoubleNullPathW(wcsPath);

	sos.hwnd = NULL;
	sos.wFunc = FO_DELETE;
	sos.pFrom = wcsFrom.c_str();
	sos.pTo = NULL;
	sos.fFlags = FOF_NO_UI;
	if ((flag & CZ_FILE_TO_RECOVERY) != 0) sos.fFlags |= FOF_ALLOWUNDO;
	if (SHFileOperationW(&sos) != 0)
	{
		CZ_LOG_ERRORW(L"");
		return false;
	}
	return true;
}

bool cz_file_DeletePathA(IN stringc& strPath, u32 flag /* = CZ_FILE_NULL */)
{
	if (!cz_file_IsPathExistsA(strPath)) return true;

	SHFILEOPSTRUCTA sos;
	string strFrom = cz_file_in_GetDoubleNullPathA(strPath);

	sos.hwnd = NULL;
	sos.wFunc = FO_DELETE;
	sos.pFrom = strFrom.c_str();
	sos.pTo = NULL;
	sos.fFlags = FOF_NO_UI;
	if ((flag & CZ_FILE_TO_RECOVERY) != 0) sos.fFlags |= FOF_ALLOWUNDO;
	if (SHFileOperationA(&sos) != 0)
	{
		CZ_LOG_ERRORA("");
		return false;
	}
	return true;
}

/* RenamePathX ---------------------------------------------------------------------------------------------*/
bool cz_file_RenamePathW(IN wstring& wcsPath, IN wstringc& wcsNewName)
{
	if (!cz_file_IsPathExistsW(wcsPath))
	{
		CZ_LOG_ERRORW(L"");
		return false;
	}

	SHFILEOPSTRUCTW sos;
	wstring wcsFrom = cz_file_in_GetDoubleNullPathW(wcsPath);
	wstring wcsTo = cz_file_in_GetDoubleNullPathW(cz_file_GetParentDirW(wcsPath) + wcsNewName);

	sos.hwnd = NULL;
	sos.wFunc = FO_RENAME;
	sos.pFrom = wcsFrom.c_str();
	sos.pTo = wcsTo.c_str();
	sos.fFlags = FOF_NO_UI;
	if (SHFileOperationW(&sos) != 0)
	{
		return false;
	}
	return true;
}

bool cz_file_RenamePathA(IN string& strPath, IN stringc& strNewName)
{
	if (!cz_file_IsPathExistsA(strPath))
	{
		CZ_LOG_ERRORA("");
		return false;
	}

	SHFILEOPSTRUCTA sos;
	string strFrom = cz_file_in_GetDoubleNullPathA(strPath);
	string strTo = cz_file_in_GetDoubleNullPathA(cz_file_GetParentDirA(strPath) + strNewName);

	sos.hwnd = NULL;
	sos.wFunc = FO_RENAME;
	sos.pFrom = strFrom.c_str();
	sos.pTo = strTo.c_str();
	sos.fFlags = FOF_NO_UI;
	if (SHFileOperationA(&sos) != 0)
	{
		return false;
	}
	return true;
}

/* GetExeDirX ----------------------------------------------------------------------------------------------*/
wstring cz_file_GetExeDirW()
{
	wchar s[CZ_MAX_PATHW + 1];
	if (GetModuleFileNameW(NULL, s, CZ_MAX_PATHW) == 0)
	{
		CZ_LOG_ERRORW(L"");
		return L"";
	}
	s[CZ_MAX_PATHW] = 0;
	return cz_string_ReverseGetLeftW(s, L'\\', CZ_STRING_INCLUDE);
}

string cz_file_GetExeDirA()
{
	char s[CZ_MAX_PATHA + 1];
	if (GetModuleFileNameA(NULL, s, CZ_MAX_PATHA) == 0)
	{
		CZ_LOG_ERRORA("");
		return "";
	}
	s[CZ_MAX_PATHA] = 0;
	return cz_string_ReverseGetLeftA(s, '\\', CZ_STRING_INCLUDE);
}

/* GetCurrentDriveX ----------------------------------------------------------------------------------------*/
wstring cz_file_GetExeDriveW()
{
	wchar s[CZ_MAX_PATHW + 1];
	if (GetModuleFileNameW(NULL, s, CZ_MAX_PATHW) == 0)
	{
		CZ_LOG_ERRORW(L"");
		return L"";
	}
	s[CZ_MAX_PATHW] = 0;
	return cz_string_GetLeftW(s, L'\\', CZ_STRING_INCLUDE);
}

string cz_file_GetExeDriveA()
{
	char s[CZ_MAX_PATHA + 1];
	if (GetModuleFileNameA(NULL, s, CZ_MAX_PATHA) == 0)
	{
		CZ_LOG_ERRORA("");
		return "";
	}
	s[CZ_MAX_PATHA] = 0;
	return cz_string_GetLeftA(s, '\\', CZ_STRING_INCLUDE);
}

/* GetParentDirX -------------------------------------------------------------------------------------------*/
wstring cz_file_GetParentDirW(IN wstringc& wcsPath)
{
	if (cz_file_IsDirFormatW(wcsPath))
	{
		return cz_string_ReverseGetLeftW(cz_string_ReverseGetLeftW(wcsPath, L'\\'), L'\\', CZ_STRING_INCLUDE | CZ_STRING_EMPTY);
	}
	else
	{
		return cz_string_ReverseGetLeftW(wcsPath, L'\\', CZ_STRING_INCLUDE | CZ_STRING_EMPTY);
	}
}

string cz_file_GetParentDirA(IN stringc& strPath)
{
	if (cz_file_IsDirFormatA(strPath))
	{
		return cz_string_ReverseGetLeftA(cz_string_ReverseGetLeftA(strPath, '\\'), '\\', CZ_STRING_INCLUDE | CZ_STRING_EMPTY);
	}
	else
	{
		return cz_string_ReverseGetLeftA(strPath, '\\', CZ_STRING_INCLUDE | CZ_STRING_EMPTY);
	}
}

/* GetPathNameA --------------------------------------------------------------------------------------------*/
wstring cz_file_GetPathNameW(IN wstringc& wcsPath)
{
	if (cz_file_IsDirFormatW(wcsPath))
	{
		return cz_string_ReverseGetRightW(cz_string_ReverseGetLeftW(wcsPath, L'\\'), L'\\');
	}
	else
	{
		return cz_string_ReverseGetRightW(wcsPath, L'\\');
	}
}

string cz_file_GetPathNameA(IN stringc& strPath)
{
	if (cz_file_IsDirFormatA(strPath))
	{
		return cz_string_ReverseGetRightA(cz_string_ReverseGetLeftA(strPath, '\\'), '\\');
	}
	else
	{
		return cz_string_ReverseGetRightA(strPath, '\\');
	}
}

/* IsDirFormatX --------------------------------------------------------------------------------------------*/
bool cz_file_IsDirFormatW(IN wstringc& wcsPath)
{
	u32 size = wcsPath.size();
	if ((size == 0) || (wcsPath[size-1] != L'\\')) return false;
	return true;
}

bool cz_file_IsDirFormatA(IN stringc& strPath)
{
	u32 size = strPath.size();
	if ((size == 0) || (strPath[size-1] != '\\')) return false;
	return true;
}

/* IsPathExistsX -------------------------------------------------------------------------------------------*/
bool cz_file_IsPathExistsW(wstring const& wcsPath)
{	
	if (!PathFileExistsW(wcsPath.c_str())) return false;
	return true;
}

bool cz_file_IsPathExistsA(string const& strPath)
{
	if (!PathFileExistsA(strPath.c_str())) return false;
	return true;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
wstring cz_file_in_GetDoubleNullPathW(IN wstring const& wcsPath)
{
	wstring wcs;
	wcs = wcsPath;
	if (!cz_file_IsDirFormatW(wcs)) wcs.append(1, L'\0');
	else wcs[wcs.size() - 1] = 0;
	return wcs;
}

string cz_file_in_GetDoubleNullPathA(IN stringc& strPath)
{
	string str;
	str = strPath;
	if (!cz_file_IsDirFormatA(str)) str.append(1, L'\0');
	else str[str.size() - 1] = 0;
	return str;
}

